﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;

namespace MabiCommerce
{
    enum BanditLevels
    {
        Newbie = 0,
        Rookie = 1,
        Trained = 2,
        Hardened = 3,
        Veteran = 4,
        Master = 5
    }
    public partial class Map : Form
    {
        private CommerceRun run;
        private Town start;
        public Map(CommerceRun selected, Town startTown)
        {
            run = selected;
            start = startTown;
            InitializeComponent();
            label2.Text = "ducats to buy my load of " + selected.TheItem.Name + "s.";
            foreach (BanditLevels b in Enum.GetValues(typeof(BanditLevels)))
            {
                Label l = new Label();
                l.AutoSize = true;
                l.Font = label3.Font;
                l.Text = b.ToString();
                l.BackColor = fills[b];
                l.ForeColor = Invert(fills[b]);
                flowLayoutPanel1.Controls.Add(l);
            }
        }

        protected override void OnFormClosed(FormClosedEventArgs e)
        {
            base.OnFormClosed(e);
            this.Dispose();
        }

        private Color Invert(Color c)
        {
            return Color.FromArgb(255 - c.A, 255 - c.R, 255 - c.B, 255 - c.G);
        }

        private void updateMapBtn_Click(object sender, EventArgs e)
        {
            int cost = (int)totalCost.Value, townsPassed = 0;

            Dictionary<Town, BanditLevels> banditLevels = new Dictionary<Town, BanditLevels>();

            if (run.TheRoute.EndTowns[0] != start)
            {
                run.TheRoute.EndTowns.Reverse();
                if ( run.TheRoute.Waypoints.Count != 0 && ! run.TheRoute.Waypoints[0].Paths.Any(new Func<Path, bool>((p) => { return p.Towns.Contains(run.TheRoute.EndTowns[0]); })))
                    run.TheRoute.Waypoints.Reverse();
            }

            banditLevels.Add(run.TheRoute.EndTowns[0], getBanditLevel(cost, 0, 0));

            for (int i = 0; i < run.TheRoute.Waypoints.Count; i++)
            {
                banditLevels.Add(run.TheRoute.Waypoints[i], getBanditLevel(cost, run.TheItem.Profits[run.TheRoute.Waypoints[i]] * run.NumberOfItems, townsPassed));
                townsPassed++;
            }

            banditLevels.Add(run.TheRoute.EndTowns[1], getBanditLevel(cost, run.TheItem.Profits[run.TheRoute.EndTowns[1]] * run.NumberOfItems, townsPassed));

            Bitmap img = (Bitmap)Image.FromFile(@"data\map\MasterMap.png");

            using (Graphics g = Graphics.FromImage(img))
            {
                int i;
                mapTown(run.TheRoute.EndTowns[0], banditLevels[run.TheRoute.EndTowns[0]], g);

                for (i = 0; i < run.TheRoute.Waypoints.Count; i++)
                {
                    if (i == 0)
                        mapPath(run.TheRoute.EndTowns[0], run.TheRoute.Waypoints[i], banditLevels[run.TheRoute.EndTowns[0]], banditLevels[run.TheRoute.Waypoints[i]], g);
                    else
                        mapPath(run.TheRoute.Waypoints[i-1], run.TheRoute.Waypoints[i], banditLevels[run.TheRoute.Waypoints[i-1]], banditLevels[run.TheRoute.Waypoints[i]], g);

                    mapTown(run.TheRoute.Waypoints[i], banditLevels[run.TheRoute.Waypoints[i]], g);
                }
                if (i != 0)
                    mapPath(run.TheRoute.Waypoints[i-1], run.TheRoute.EndTowns[1], banditLevels[run.TheRoute.Waypoints[i-1]], banditLevels[run.TheRoute.EndTowns[1]], g);
                else
                    mapPath(run.TheRoute.EndTowns[0], run.TheRoute.EndTowns[1], banditLevels[run.TheRoute.EndTowns[0]], banditLevels[run.TheRoute.EndTowns[1]], g);

                mapTown(run.TheRoute.EndTowns[1], banditLevels[run.TheRoute.EndTowns[1]], g);

            }

            pictureBox1.Image.Dispose();
            pictureBox1.Image = img;
        }

        private BanditLevels getBanditLevel(int cost, int profit, int townsPassed)
        {
            int level, costProfit = cost + profit;
            if (costProfit < 20 * 1000)
                level = (int)BanditLevels.Rookie;
            else if (costProfit < 55 * 1000)
                level = (int)BanditLevels.Trained;
            else if (costProfit < 100 * 1000)
                level = (int)BanditLevels.Hardened;
            else if (costProfit < 145 * 1000)
                level = (int)BanditLevels.Veteran;
            else
                level = (int)BanditLevels.Master;

            level += townsPassed;


            if (level < 0)
                level = 0;
            if (level > 5)
                level = 5;

            return (BanditLevels)level;
        }

        Dictionary<BanditLevels, Color> fills = new Dictionary<BanditLevels, Color>()
        {
            {BanditLevels.Newbie, Color.LimeGreen},
            {BanditLevels.Rookie, Color.GreenYellow},
            {BanditLevels.Trained, Color.Yellow},
            {BanditLevels.Hardened, Color.Orange},
            {BanditLevels.Veteran, Color.Red},
            {BanditLevels.Master, Color.DarkRed}
        };

        private void mapPath(Town start, Town end, BanditLevels startLevel, BanditLevels endLevel, Graphics g)
        {
            Path p = start.Paths.Find(new Predicate<Path>((pa) => { return pa.Towns.Contains(end); }));
            if (p.Map == null)
                return;
            Color sL, eL;
            if (p.Towns[0] == start)
            {
                sL = fills[startLevel];
                eL = fills[endLevel];
            }
            else
            {
                sL = fills[endLevel];
                eL = fills[startLevel];
            }
            Bitmap b = new Bitmap(p.Map);
            b.SetResolution(g.DpiX, g.DpiY);
            colorPathBitmap(ref b, p.MapSplitLeft, p.MapSplitRight, sL, eL);
            g.DrawImageUnscaled(b, p.MapLocation);
            b.Dispose();
        }

        private unsafe void colorPathBitmap(ref Bitmap img, Point Left, Point Right, Color LeftColor, Color RightColor)
        {
            if (img.PixelFormat != PixelFormat.Format32bppArgb)
                throw new InvalidOperationException("A pixel format of " + img.PixelFormat + " is not supported. Please use a 32bpp ARGB image");

            double m;
            m = (double)(Right.Y - Left.Y) / (Right.X - Left.X);
            double b = Left.Y - m * Left.X;

            bool vertical = double.IsInfinity(m);

            BitmapData bmd = img.LockBits(new Rectangle(0, 0, img.Width, img.Height), ImageLockMode.ReadWrite, img.PixelFormat);
            for (int y = 0, maxY = bmd.Height; y < maxY; y++)
            {
                for (int x = 0, maxX = bmd.Width; x < maxX; x++)
                {

                    byte* R, G, B, A;
                    B = (byte*)bmd.Scan0 + x * 4 + y * bmd.Stride;
                    G = B + 1;
                    R = B + 2;
                    A = B + 3;

                    if (*R == 0xFF && *G == 0x69 && *B == 0xB4 && *A == 0xFF)
                    {
                        Color fill;
                        if (vertical)
                        {
                            fill = (Left.X < x ? LeftColor : RightColor);
                        }
                        else
                        {
                            fill = ((m * x + b) > y ? LeftColor : RightColor);
                        }
                        *R = fill.R;
                        *G = fill.G;
                        *B = fill.B;
                        *A = fill.A;
                    }
                }
            }

            img.UnlockBits(bmd);
        }


        private void mapTown(Town t, BanditLevels Level, Graphics g)
        {
            if (t.Map == null)
                return;
            Bitmap b = new Bitmap(t.Map);
            b.SetResolution(g.DpiX, g.DpiY);
            colorTownBitmap(ref b, fills[Level]);
            g.DrawImageUnscaled(b, t.MapLocation);
            b.Dispose();
        }

        private unsafe void colorTownBitmap(ref Bitmap img, Color fill)
        {
            if (img.PixelFormat != PixelFormat.Format32bppArgb)
                throw new InvalidOperationException("A pixel format of " + img.PixelFormat + " is not supported. Please use a 32bpp ARGB image");

            BitmapData bmd = img.LockBits(new Rectangle(0, 0, img.Width, img.Height), ImageLockMode.ReadWrite, img.PixelFormat);
            for (int y = 0, maxY = bmd.Height; y < maxY; y++)
            {
                for (int x = 0, maxX = bmd.Width; x < maxX; x++)
                {

                    byte* R, G, B, A;
                    B = (byte*)bmd.Scan0 + x * 4 + y * bmd.Stride;
                    G = B + 1;
                    R = B + 2;
                    A = B + 3;

                    if (*R == 0xFF && *G == 0x69 && *B == 0xB4 && *A == 0xFF)
                    {
                        *R = fill.R;
                        *G = fill.G;
                        *B = fill.B;
                        *A = fill.A;
                    }
                }
            }

            img.UnlockBits(bmd);
        }
    }
}
